﻿using CWCS.Common;
using CWCS.Entity;
using CWCS.Entity.Convery;
using CWCS.Entity.SRM;
using HslCommunication;
using HslCommunication.Profinet.Siemens;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using CWCS.Core.Library.PLCManager;
using Nti56.Modbus.Communication.Models;
using Nti56.Modbus.Communication.Services;
using System.Data;

namespace CWCS.Core.Library.SmartPLCManager
{
    public class SmartPLC : PLCHelper
    {
        int result = 0;
        string msg = string.Empty;
        public static List<SmartEntity> smartInfo = new List<SmartEntity>();
        public static bool IsInit = false;
        private string local_ip;
        private readonly object objLoc = new object();
        public Dictionary<string, bool> PLCConnectStatus = new Dictionary<string, bool>();
        private Dictionary<string, TimerManager> pftDic = new Dictionary<string, TimerManager>();
        private delegate void ReadOPCInfos(object info);
        private event ReadOPCInfos ReadEquipOPCInfo;
        private delegate void ReConnetPLC(string ip, int retryCount);
        private event ReConnetPLC STAReConnectPLC;
        private delegate void ReSmartConnetPLC(string ip, int retryCount);
        private event ReSmartConnetPLC SCReSmartConnectPLC;
        public int _ReadDBMaxLength = 2000;
        //堆垛机
        ModbusReadWriteService readService = new ModbusReadWriteService();
        ModbusReadWriteService writeService = new ModbusReadWriteService();
        public static Dictionary<string, ModbusTcpClient> modbusReadClients = new Dictionary<string, ModbusTcpClient>();
        public static Dictionary<string, ModbusTcpClient> modbusWriteClients = new Dictionary<string, ModbusTcpClient>();
        protected static Dictionary<string, ModbusConnectionInfo> ModbusList = new Dictionary<string, ModbusConnectionInfo>();//PLC列表
        public string FaceCode = ConfigurationManager.AppSettings["FaceCode"].ToString().Trim();
        public string TrayMode = ConfigurationManager.AppSettings["TrayMode"].ToString().Trim();
        public void InitData(List<SmartEntity> lst, ref string error)
        {
            try
            {
                foreach (var item in lst as List<SmartEntity>)
                {
                    local_ip = item.Key_ip;
                    if (item.equipmenttype == "SC")
                    {
                        if (!ModbusList.ContainsKey(item.Key_ip))
                        {
                            ModbusConnectionInfo connectionInfo = new ModbusConnectionInfo()
                            {
                                Ip = IPAddress.Parse(item.Key_ip),
                                Port = item.port,
                                Station = 1
                            };
                            ModbusList.Add(item.Key_ip, connectionInfo);
                            PLCConnectStatus.Add(item.Key_ip, false);
                            var Readconnect = ModbusConnection.Connection(connectionInfo, "R" + item.Key_ip);
                            var Writeconnect = ModbusConnection.Connection(connectionInfo, "W" + item.Key_ip);
                            modbusReadClients[item.Key_ip] = Readconnect.Value;
                            modbusWriteClients[item.Key_ip] = Writeconnect.Value;
                            if (Readconnect.Value.Client.Connected && Writeconnect.Value.Client.Connected)
                            {
                                if (!PLCConnectStatus.ContainsKey(item.Key_ip))
                                {
                                    PLCConnectStatus.Add(item.Key_ip, true);
                                }
                            }
                            else
                            {
                                if (!PLCConnectStatus.ContainsKey(item.Key_ip))
                                {
                                    PLCConnectStatus.Add(item.Key_ip, false);
                                }
                            }
                        }
                    }
                    else
                    {
                        if (!PLCList.ContainsKey(local_ip))
                        {
                            SiemensS7Net siemens = new SiemensS7Net(SiemensPLCS.S1500)
                            {
                                IpAddress = local_ip,
                                Port = item.port,
                                Slot = 1,
                                ConnectTimeOut = 1000
                            };
                            PLCList.Add(local_ip, siemens);

                            PLCConnectStatus.Add(local_ip, false);

                            //长链接
                            OperateResult operateResult = PLCList[local_ip].ConnectServer();
                            if (operateResult.IsSuccess)
                            {
                                if (!PLCConnectStatus.ContainsKey(item.Key_ip))
                                {
                                    PLCConnectStatus.Add(item.Key_ip, true);
                                }
                            }
                            else
                            {
                                if (!PLCConnectStatus.ContainsKey(item.Key_ip))
                                {
                                    PLCConnectStatus.Add(item.Key_ip, false);
                                }
                            }
                        }
                    }
                    SmartInit(item, local_ip);
                }
                ShowMsg("SmartInit", "智能电表初始化完成");
                IsInit = true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }
        }

        public SmartPLC()
        {
            //ReadEquipOPCInfo += new ReadOPCInfos(BatchReadSmartConveryInfo);
            //this.STAReConnectPLC += new ReConnetPLC(ReConnect);
            // this.SCReSmartConnectPLC += new SCReSmartConnectPLC(ReSmartConnect);
        }
        /// <summary>
        /// 初始化输送机
        /// </summary>
        /// <param name="si"></param>
        private void SmartInit(SmartEntity si, string strlocal_ip)
        {
            smartInfo.Add(si);
        }

        public void Run(object i_Index)
        {
            Thread threadCom = new Thread(new ParameterizedThreadStart(TimeScan));
            threadCom.IsBackground = true;
            threadCom.Start(i_Index);
        }

        private void TimeScan(object belong)
        {
            while (true)
            {
                TimerManager pfttemp;
                try
                {
                    if (!pftDic.ContainsKey(belong.ToString()))
                    {
                        pfttemp = new TimerManager();
                    }
                    else
                    {
                        pfttemp = pftDic[belong.ToString()];
                    }
                    pfttemp.Start();
                    var lst = smartInfo.Where(it => it.Belong == belong.ToString()).ToList();
                    if (lst.Count > 0)
                    {
                        foreach (SmartEntity csi in lst)
                        {
                            if (csi.equipmenttype == "Convery")
                                BatchReadSmartConveryInfo(csi);
                            else if (csi.equipmenttype == "Robot")
                                BatchReadSmartRobotInfo(csi);
                            else
                                ReadSRMSmartInfo(csi, belong);
                        }
                        pfttemp.Stop();
                    }
                }
                catch (Exception ex)
                {
                    //throw ex;
                }
                Thread.Sleep(5 * 60 * 1000);
            }
        }

        /// <summary>
        /// 读取所属线程的电表信息
        /// </summary>
        /// <param name="stationinfo"></param>
        private void BatchReadSmartConveryInfo(object obj)
        {
            SmartEntity stat = (SmartEntity)obj;
            int length = stat.Smartlength;
            int count = stat.Smartlength / _ReadDBMaxLength;
            if (stat.Smartlength % _ReadDBMaxLength > 0)
                count = count + 1;
            for (int i = 1; i <= count; i++)
            {
                byte[] smartBuffer = new byte[length];
                if (SmartReadPlc(PLCList[stat.Key_ip], stat.SmartDBAddress, stat.Smartvalue + (i - 1) * length, length, ref smartBuffer))
                {
                    stat.CFlag = true;
                    BindSmartListConvery(smartBuffer, stat, stat.Smartvalue + (i - 1) * length, stat.Smartvalue + i * length);
                }
                else
                {
                    stat.CFlag = false;
                    ReConnect(stat.Key_ip, 1);
                }
                if (!PLCConnectStatus.ContainsKey(stat.Key_ip))
                    PLCConnectStatus.Add(stat.Key_ip, stat.CFlag);
                else
                    PLCConnectStatus[stat.Key_ip] = stat.CFlag;
            }
        }
        #region 数据解析
        /// <summary>
        /// 绑定物流线智能电表信息
        /// </summary>
        /// <param name="stationno"></param>
        /// <param name="byt"></param>
        private void BindSmartConveryInfo(string kep_ip, string equipmentnumber, byte[] byt)
        {
            SmartEntity si = smartInfo.Find(
              delegate (SmartEntity ss)
              {
                  return ss.equipmentnumber == equipmentnumber;
              });
            if (si != null)
            {
                byte[] byteArray = new byte[4];
                Array.Copy(byt, 0, byteArray, 0, 4);
                si.Smart_C_Info.CombinedActivePower1 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                Array.Copy(byt, 4, byteArray, 0, 4);
                si.Smart_C_Info.TotalPositiveActivePower1 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                Array.Copy(byt, 8, byteArray, 0, 4);
                si.Smart_C_Info.CombinedActivePower2 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                Array.Copy(byt, 12, byteArray, 0, 4);
                si.Smart_C_Info.TotalPositiveActivePower2 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                if (si.Smart_C_Info.ZoneCode == "FR")
                {
                    Array.Copy(byt, 16, byteArray, 0, 4);
                    si.Smart_C_Info.CombinedActivePower3 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                    Array.Copy(byt, 20, byteArray, 0, 4);
                    si.Smart_C_Info.TotalPositiveActivePower3 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                    Array.Copy(byt, 24, byteArray, 0, 4);
                    si.Smart_C_Info.CombinedActivePower4 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                    Array.Copy(byt, 28, byteArray, 0, 4);
                    si.Smart_C_Info.TotalPositiveActivePower4 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                }
                if (si.equipmentnumber == "ZKOA" || si.equipmentnumber == "ZKOF")
                {
                    si.Smart_C_Info.CombinedActivePower = si.Smart_C_Info.CombinedActivePower1;
                    si.Smart_C_Info.TotalPositiveActivePower = si.Smart_C_Info.TotalPositiveActivePower1;
                }
                else if (si.equipmentnumber == "ZKOB" || si.equipmentnumber == "ZKOC")
                {
                    si.Smart_C_Info.CombinedActivePower = si.Smart_C_Info.CombinedActivePower2;
                    si.Smart_C_Info.TotalPositiveActivePower = si.Smart_C_Info.TotalPositiveActivePower2;
                }
                else if (si.equipmentnumber == "ZKOD")
                {
                    si.Smart_C_Info.CombinedActivePower = si.Smart_C_Info.CombinedActivePower3;
                    si.Smart_C_Info.TotalPositiveActivePower = si.Smart_C_Info.TotalPositiveActivePower3;
                }
                else if (si.equipmentnumber == "ZKOE")
                {
                    si.Smart_C_Info.CombinedActivePower = si.Smart_C_Info.CombinedActivePower4;
                    si.Smart_C_Info.TotalPositiveActivePower = si.Smart_C_Info.TotalPositiveActivePower4;
                }
            }
            si.Smart_C_Info.equipmentnumber = equipmentnumber;
            si.Smart_C_Info.equipmenttype = si.equipmenttype;
            ShowEquipmentTaskInfo(si.Smart_C_Info);//业务处理
        }
        /// <summary>
        /// 解析物流线智能电表数据
        /// </summary>
        /// <param name="byt"></param>
        /// <param name="cr"></param>
        private void BindSmartListConvery(byte[] byt, SmartEntity si, int startValue, int endValue)
        {
            //lock (obj)
            {
                int i_Length = si.Smartlength;
                if (si != null)
                {
                    byte[] bytetemp = new byte[si.Smartlength];

                    Array.Copy(byt, startValue, bytetemp, 0, si.Smartlength);
                    if (bytetemp != null)
                    {
                        //可采用异步方式
                        BindSmartConveryInfo(si.Key_ip, si.equipmentnumber, bytetemp);//绑定信息
                    }
                }
                i_Length = i_Length - si.Smartlength;
            }

        }
        #endregion
        /// <summary>
        /// 读取机械手智能电表信息
        /// </summary>
        /// <param name="stationinfo"></param>
        private void BatchReadSmartRobotInfo(object obj)
        {
            SmartEntity stat = (SmartEntity)obj;
            int length = stat.Smartlength;
            int count = stat.Smartlength / _ReadDBMaxLength;
            if (stat.Smartlength % _ReadDBMaxLength > 0)
                count = count + 1;
            for (int i = 1; i <= count; i++)
            {
                byte[] smartBuffer = new byte[length];
                if (SmartReadPlc(PLCList[stat.Key_ip], stat.SmartDBAddress, stat.Smartvalue + (i - 1) * length, length, ref smartBuffer))
                {
                    stat.CFlag = true;
                    BindSmartListRobot(smartBuffer, stat, stat.Smartvalue + (i - 1) * length, stat.Smartvalue + i * length);
                }
                else
                {
                    stat.CFlag = false;
                    ReConnect(stat.Key_ip, 1);
                }
                if (!PLCConnectStatus.ContainsKey(stat.Key_ip))
                    PLCConnectStatus.Add(stat.Key_ip, stat.CFlag);
                else
                    PLCConnectStatus[stat.Key_ip] = stat.CFlag;
            }
        }
        /// <summary>
        /// 解析机械手智能电表数据
        /// </summary>
        /// <param name="byt"></param>
        /// <param name="si"></param>
        /// <param name="startValue"></param>
        /// <param name="endValue"></param>
        private void BindSmartListRobot(byte[] byt, SmartEntity si, int startValue, int endValue)
        {
            //lock (obj)
            {
                int i_Length = si.Smartlength;
                if (si != null)
                {
                    byte[] bytetemp = new byte[si.Smartlength];

                    Array.Copy(byt, startValue, bytetemp, 0, si.Smartlength);
                    if (bytetemp != null)
                    {
                        //可采用异步方式
                        BindSmartRobotInfo(si.Key_ip, si.equipmentnumber, bytetemp);//绑定信息
                    }
                }
                i_Length = i_Length - si.Smartlength;
            }

        }
        /// <summary>
        /// 机械手绑定智能电表信息
        /// </summary>
        /// <param name="stationno"></param>
        /// <param name="byt"></param>
        private void BindSmartRobotInfo(string kep_ip, string equipmentnumber, byte[] byt)
        {
            SmartEntity si = smartInfo.Find(
              delegate (SmartEntity ss)
              {
                  return ss.equipmentnumber == equipmentnumber;
              });
            if (si != null)
            {
                byte[] byteArray = new byte[4];
                Array.Copy(byt, 0, byteArray, 0, 4);
                si.Smart_C_Info.CombinedActivePower1 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                Array.Copy(byt, 4, byteArray, 0, 4);
                si.Smart_C_Info.TotalPositiveActivePower1 = Math.Round(System.BitConverter.ToSingle(byteArray.Reverse().ToArray(), 0), 2);
                si.Smart_C_Info.CombinedActivePower = si.Smart_C_Info.CombinedActivePower1;
                si.Smart_C_Info.TotalPositiveActivePower = si.Smart_C_Info.TotalPositiveActivePower1;
            }
            ShowEquipmentTaskInfo(si.Smart_C_Info);//业务处理
        }
        /// <summary>
        /// 重新连接
        /// </summary>
        /// <param name="strIP"></param>
        /// <param name="retryCount"></param>
        private void ReConnect(string strIP, int retryCount = 1)
        {
            try
            {
                //if (STAReConnectPLC != null)
                //{
                    lock (objLoc)
                    {
                        ShowMsg("Break", string.Format("输送机智能电表PLC:{0},连接断开,系统开始自动重连...", strIP));
                        if (PLCList.ContainsKey(strIP))
                        {
                            bool flag = true;
                            int i_Count = 1;
                            while (flag)
                            {
                                if (i_Count > retryCount)
                                    break;
                                //断开连接
                                PLCList[strIP].ConnectClose();
                                ShowMsg("Break", string.Format("智能电表PLC：{0}，尝试连接次数：{1}", strIP, i_Count));
                                //长链接
                                OperateResult connect = PLCList[strIP].ConnectServer();

                                if (connect.IsSuccess)
                                {
                                    ShowMsg("Break", string.Format("智能电表PLC：{0}，连接成功", strIP, i_Count));
                                    flag = false;
                                    break;
                                }
                                else
                                {
                                    i_Count++;
                                }
                            }
                        }
                    }
                //}
            }
            catch (Exception e)
            {
                ShowMsg("Break", string.Format("PLC：{0},智能电表重新链接失败！", strIP));
            }
        }

        /// <summary>
        /// 堆垛机智能电表重新连接
        /// </summary>
        /// <param name="strIP"></param>
        /// <param name="retryCount"></param>
        private void ReSmartConnect(string strIP, int retryCount = 1)
        {
            try
            {
                //if (SCReSmartConnectPLC != null)
                //{
                    lock (objLoc)
                    {
                        ShowMsg("Break", string.Format("堆垛机智能电表PLC:{0},连接断开,系统开始自动重连...", strIP));
                        if (ModbusList.ContainsKey(strIP))
                        {
                            bool flag = true;
                            int i_Count = 1;
                            while (flag)
                            {
                                if (i_Count > retryCount)
                                    break;
                                //断开连接
                                modbusReadClients[strIP].Client?.Close();
                                modbusWriteClients[strIP].Client?.Close();
                                ShowMsg("Break", string.Format("堆垛机智能电表PLC：{0}，尝试连接次数：{1}", strIP, i_Count));
                                var Readconnect = ModbusConnection.Connection(ModbusList[strIP], "R" + strIP);
                                var Writeconnect = ModbusConnection.Connection(ModbusList[strIP], "W" + strIP);
                                modbusReadClients[strIP] = Readconnect.Value;
                                modbusWriteClients[strIP] = Writeconnect.Value;
                                if (Readconnect.Value.Client.Connected && Writeconnect.Value.Client.Connected)
                                {
                                    ShowMsg("Break", string.Format("堆垛机智能电表PLC：{0}，连接成功", strIP, i_Count));
                                    flag = false;
                                    break;
                                }
                                else
                                {
                                    i_Count++;
                                }
                            }
                        }
                    }
                //}
            }
            catch (Exception e)
            {
                ShowMsg("Break", string.Format("PLC：{0},堆垛机智能电表重新链接失败！", strIP));
            }
        }
        public string[] ReadStaInfo(string kep_ip)
        {
            string[] info = new string[8];
            SmartEntity si = smartInfo.Find(
                 delegate (SmartEntity ss)
                 {
                     return ss.Key_ip == kep_ip.ToString();
                 }
             );
            if (si != null)
            {
                Byte[] SmartBuffer = new byte[si.Smartlength];
                if (ReadPlc(PLCList[si.Key_ip], si.SmartDBAddress, si.Smartvalue, si.Smartlength, ref SmartBuffer))
                {
                    si.CFlag = true;
                    si.Smart_C_Info.CombinedActivePower1 = SmartBuffer[0] * 256 * 256 * 256 + SmartBuffer[1] * 256 * 256 + SmartBuffer[2] * 256 + SmartBuffer[3];//任务信息
                    si.Smart_C_Info.TotalPositiveActivePower1 = SmartBuffer[4] * 256 * 256 * 256 + SmartBuffer[5] * 256 * 256 + SmartBuffer[6] * 256 + SmartBuffer[7];//任务信息
                    si.Smart_C_Info.CombinedActivePower2 = SmartBuffer[8] * 256 * 256 * 256 + SmartBuffer[9] * 256 * 256 + SmartBuffer[10] * 256 + SmartBuffer[11];//任务信息 
                    si.Smart_C_Info.TotalPositiveActivePower2 = SmartBuffer[12] * 256 * 256 * 256 + SmartBuffer[13] * 256 * 256 + SmartBuffer[14] * 256 + SmartBuffer[15];//任务信息
                    if (si.Smart_C_Info.ZoneCode == "FR")
                    {
                        si.Smart_C_Info.CombinedActivePower3 = SmartBuffer[16] * 256 * 256 * 256 + SmartBuffer[17] * 256 * 256 + SmartBuffer[18] * 256 + SmartBuffer[19];//任务信息
                        si.Smart_C_Info.TotalPositiveActivePower3 = SmartBuffer[20] * 256 * 256 * 256 + SmartBuffer[21] * 256 * 256 + SmartBuffer[22] * 256 + SmartBuffer[23];//任务信息
                        si.Smart_C_Info.CombinedActivePower4 = SmartBuffer[24] * 256 * 256 * 256 + SmartBuffer[25] * 256 * 256 + SmartBuffer[26] * 256 + SmartBuffer[27];//任务信息
                        si.Smart_C_Info.TotalPositiveActivePower4 = SmartBuffer[28] * 256 * 256 * 256 + SmartBuffer[29] * 256 * 256 + SmartBuffer[30] * 256 + SmartBuffer[31];//任务信息
                    }
                }
                else
                {
                    si.CFlag = false;
                }
                info[0] = si.Smart_C_Info.CombinedActivePower1.ToString();
                info[1] = si.Smart_C_Info.TotalPositiveActivePower1.ToString();
                info[2] = si.Smart_C_Info.CombinedActivePower2.ToString();
                info[3] = si.Smart_C_Info.TotalPositiveActivePower2.ToString();
                info[4] = si.Smart_C_Info.CombinedActivePower3.ToString();
                info[5] = si.Smart_C_Info.TotalPositiveActivePower3.ToString();
                info[6] = si.Smart_C_Info.CombinedActivePower4.ToString();
                info[7] = si.Smart_C_Info.TotalPositiveActivePower4.ToString();
            }
            return info;
        }
        /// <summary>
        /// 读取堆垛机施耐德PLC
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="belong"></param>
        private void ReadSRMSmartInfo(object obj, object belong)
        {
            if (obj != null)
            {
                SmartEntity sc = (SmartEntity)obj;
                byte[] scBuffer = new byte[sc.Smartlength * 2];
                if (modbusReadClients[sc.Key_ip].Client.Connected)
                {
                    var result = readService.ReadByte(sc.SmartDBAddress, (ushort)(sc.Smartlength * 2), modbusReadClients[sc.Key_ip], "R" + sc.equipmentnumber);
                    if (result.IsSucceed)
                    {
                        result.Value.CopyTo(scBuffer, 0);
                        byte[] byttemp = new byte[scBuffer.Length - 4];
                        Array.Copy(scBuffer, 4, byttemp, 0, byttemp.Length);
                        byttemp = byttemp.Select((x, i) => new { x, i }).GroupBy(x => x.i / 2).SelectMany(x => new byte[] { x.Last().x, x.First().x }).ToArray();
                        Array.Copy(byttemp, 0, scBuffer, 4, byttemp.Length);
                        sc.connectstatus = 1;
                        UpdateCRCStatus(sc.equipmentnumber, "Info", scBuffer);
                    }
                    else
                    {
                        ReSmartConnect(sc.Key_ip, 1);
                        sc.connectstatus = 0;
                        UpdateCRCStatus(sc.equipmentnumber, "Break", scBuffer);
                    }
                }
                else
                {
                    ReSmartConnect(sc.Key_ip, 1);
                    sc.connectstatus = 0;
                    UpdateCRCStatus(sc.equipmentnumber, "Break", scBuffer);
                }
            }
        }

        public string UpdateCRCStatus(string scno, string str, byte[] msg)
        {
            string srmLog = "";
            SmartEntity SrmInfo = smartInfo.Find(
                delegate (SmartEntity info)
                {
                    return info.equipmentnumber == scno;
                }
            );
            if (SrmInfo != null)
            {
                if (msg.Length > 38)
                {
                    string SCStatus = string.Empty;
                    byte[] byteArray = new byte[4];

                    SrmInfo.Smart_C_Info.CombinedActivePower = int.Parse(msg[0].ToString()) * 256 + int.Parse(msg[1].ToString());
                    SrmInfo.Smart_C_Info.TotalPositiveActivePower = int.Parse(msg[40].ToString());
                }
                ShowEquipmentTaskInfo(SrmInfo.Smart_C_Info);//业务处理
            }
            return srmLog;
        }
        public override string[] ReadPLCInfo(string EquipNum, int index = 0)
        {
            throw new NotImplementedException();
        }
    }
}
